#include "stdafx.h"
#include "resource.h"
#include "EXScrollBar.h"
#include "EXListCtrlWnd.h"

// CEXScrollBar
#define DEF_TIMER_LEFT_PRESSED_ID			1
#define DEF_TIMER_LEFT_PRESSED_ELAPSE		100

#define DEF_TIMER_RIGHT_PRESSED_ID			2
#define DEF_TIMER_RIGHT_PRESSED_ELAPSE		100

#define DEF_TIMER_PAGE_LEFT_PRESSED_ID		3
#define DEF_TIMER_PAGE_LEFT_PRESSED_ELAPSE	100

#define DEF_TIMER_PAGE_RIGHT_PRESSED_ID		4
#define DEF_TIMER_PAGE_RIGHT_PRESSED_ELAPSE	100

#define DEF_TIMER_LEFT_LEAVE_ID				5
#define DEF_TIMER_LEFT_LEAVE_ELAPSE			10

#define DEF_TIMER_RIGHT_LEAVE_ID			6
#define DEF_TIMER_RIGHT_LEAVE_ELAPSE		10

IMPLEMENT_DYNAMIC(CEXScrollBar, CWnd)

CEXScrollBar::CEXScrollBar()
{
	m_nMin = 0;
	m_nMax = 0;
	m_nPage = 0;
	m_nPos = 0;
	m_nTrackPos = 0;
	m_bHorizontal = TRUE;
	m_nLeftUpTimerID = 0;
	m_nRightDownTimerID = 0;
	m_nPageLeftUpTimerID = 0;
	m_nPageRightDownTimerID = 0;
	m_nPrevMax = 0;
	m_ptPrevPos.x = 0;
	m_ptPrevPos.y = 0;
	m_bClick = FALSE;
	m_bContinued = FALSE;
	m_nArrowSize = GetSystemMetrics(SM_CXHSCROLL);
	m_siThumb.cx = 0;
	m_siThumb.cy = 0;
	m_bSetLeftUpBitmap = FALSE;
	m_bSetRightDownBitmap = FALSE;
	m_bSetPageBitmap = FALSE;
	m_nLeftUpBitmapID = 0;
	m_nRightDownBitmapID = 0;
	m_nPageBitmapID = 0;
	m_LeftUpSkin = SKIN_NORMAL;
	m_RightDownSkin = SKIN_NORMAL;
	m_uLeftUpTimer = 0;
	m_uRightDownTimer = 0;
}

CEXScrollBar::~CEXScrollBar()
{
}


BEGIN_MESSAGE_MAP(CEXScrollBar, CWnd)
	ON_WM_PAINT()
	ON_WM_SIZE()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_TIMER()
	ON_WM_DESTROY()
	ON_MESSAGE(WM_DEF_MOUSEWHEEL, CEXScrollBar::OnMouseWheelNotify)
	ON_WM_MOUSEMOVE()
	ON_WM_ERASEBKGND()
END_MESSAGE_MAP()



// CEXScrollBar message handlers

void CEXScrollBar::SetResSet(CEXBaseResSet* pResSet)
{
  m_pScrollResSet = (CEXScrollBarResSet* )pResSet;
  
  if(m_pScrollResSet->m_nType == SCROLLBAR_CTRL)
  {
    SetLeftUpButtonBitmap(m_pScrollResSet->m_arrImgId.GetAt(0), 
                         m_pScrollResSet->m_arr_nImg_DivideCnt.GetAt(0));

    SetRightDownButtonBitmap(m_pScrollResSet->m_arrImgId.GetAt(1), 
                            m_pScrollResSet->m_arr_nImg_DivideCnt.GetAt(1));

    SetPageButtonBitmap(m_pScrollResSet->m_arrImgId.GetAt(2), 
                        m_pScrollResSet->m_arr_nImg_DivideCnt.GetAt(2));

    SetThumbBitmap(m_pScrollResSet->m_arrImgId.GetAt(3), 
      m_pScrollResSet->m_arrImgId.GetAt(4),m_pScrollResSet->m_arrImgId.GetAt(5), 
      m_pScrollResSet->m_arr_nImg_DivideCnt.GetAt(5), 9, 9, 9, 9);
  }
  
}

void CEXScrollBar::CalcScroll(CRect & rcClient, BOOL bResize)
{
	if (!bResize && m_nMax == m_nPrevMax)
		return;

	m_nPrevMax = m_nMax;

	m_rcLeftUpArrow = rcClient;
	m_rcRightDownArrow = rcClient;
	m_rcScroll = rcClient;
	m_rcThumb = rcClient;

	if (m_bHorizontal)
	{
		int nBtnWidth = m_nArrowSize;
		int nScrollWidth = rcClient.Width() - (nBtnWidth*2);

		m_rcLeftUpArrow.right = m_rcScroll.left = nBtnWidth;
		m_rcScroll.right = m_rcRightDownArrow.left = rcClient.Width() - nBtnWidth;

		m_rcThumb.left = m_rcLeftUpArrow.right;

		if (m_nMax > m_nPage)
		{
			m_rcThumb.right = m_rcThumb.left  + (int)((m_rcScroll.Width() / 
                       (double)(m_nMax - m_nMin))*m_nPage);

			ShowWindow(SW_SHOW);
			((CEXListCtrlWnd*)GetParent())->HScrollShow(TRUE);
		}
		else
		{
			m_rcThumb.right = m_rcThumb.left + m_rcScroll.Width();
		
			ShowWindow(SW_HIDE);
			((CEXListCtrlWnd*)GetParent())->HScrollShow(FALSE);
		}
	}
	else
	{
		int nBtnHeight = m_nArrowSize;
		int nScrollHeight = rcClient.Height() - (nBtnHeight*2);

		m_rcLeftUpArrow.bottom = m_rcScroll.top = nBtnHeight;
		m_rcScroll.bottom = m_rcRightDownArrow.top = rcClient.Height() - nBtnHeight;

		m_rcThumb.top = m_rcLeftUpArrow.bottom;
		
		if (m_nMax > m_nPage)
		{
			m_rcThumb.bottom = m_rcThumb.top  + (int)((m_rcScroll.Height() / 
                          (double)(m_nMax - m_nMin))*m_nPage);

			ShowWindow(SW_SHOW);
			((CEXListCtrlWnd*)GetParent())->VScrollShow(TRUE);
		}
		else
		{
			m_rcThumb.bottom = m_rcThumb.top + m_rcScroll.Height();

			ShowWindow(SW_HIDE);
			((CEXListCtrlWnd*)GetParent())->VScrollShow(FALSE);
		}
	}

	m_siThumb.cx = m_rcThumb.Width();
	m_siThumb.cy = m_rcThumb.Height();

	UpdateThumbPosition(rcClient);

	if (IsWindow(GetSafeHwnd()))
		RedrawWindow(NULL, NULL, RDW_UPDATENOW|RDW_INVALIDATE|RDW_NOERASE);

	if (IsWindow(m_wndThumb.GetSafeHwnd()))
	{
		m_wndThumb.MoveWindow(m_rcThumb);
	}
}

BOOL CEXScrollBar::Create(DWORD dwStyle, const RECT& rect, 
                          CWnd* pParentWnd, UINT nID)
{
	m_bHorizontal = (dwStyle & SBS_VERT) ? FALSE : TRUE;

	if (m_bHorizontal)
	{
		m_bmpLeftUp.LoadBitmap(IDB_SCROLL_LEFT);
		m_bmpRightDown.LoadBitmap(IDB_SCROLL_RIGHT);
	}
	else
	{
		m_bmpLeftUp.LoadBitmap(IDB_SCROLL_UP);
		m_bmpRightDown.LoadBitmap(IDB_SCROLL_DOWN);
	}

	m_bmpPageNormal.LoadBitmap(IDB_SCROLL_NORMAL);
	m_bmpPageSelect.LoadBitmap(IDB_SCROLL_CLICK);
	m_bmpPageFocus.LoadBitmap(IDB_SCROLL_CLICK);
	m_bmpPageDisable.LoadBitmap(IDB_SCROLL_CLICK);

	CalcScroll(CRect(rect));

	if (CWnd::Create(NULL, NULL, dwStyle|WS_CLIPCHILDREN, rect, pParentWnd, nID))
	{
		if (m_wndThumb.Create(CRect(0,0,0,0), this, -1, m_bHorizontal))
		{
			return TRUE;
		}
	}

	return FALSE;
}

BOOL CEXScrollBar::SetScrollInfo(LPSCROLLINFO lpScrollInfo, 
                                 BOOL bRedraw /*= TRUE*/)
{
	if (IsBadReadPtr(lpScrollInfo, sizeof (SCROLLINFO)))
		return FALSE;

	if (lpScrollInfo->fMask & SIF_RANGE)
	{ 
		m_nMin = lpScrollInfo->nMin;
		m_nMax = lpScrollInfo->nMax;
	}
	
	if (lpScrollInfo->fMask & SIF_PAGE)
	{
		m_nPage = lpScrollInfo->nPage;
	}
	
	if (lpScrollInfo->fMask & SIF_POS)
	{
		m_nPos = lpScrollInfo->nPos;
	}

	if (lpScrollInfo->fMask & SIF_TRACKPOS)
	{
		m_nTrackPos = lpScrollInfo->nTrackPos;
	}

	if (IsWindow(GetSafeHwnd()))
	{
		CRect rcClient;
		GetClientRect(rcClient);

		if (m_nMax != m_nPrevMax)
		{
			CalcScroll(rcClient);
		}

		UpdateThumbPosition(rcClient);
	}

	if (bRedraw)
		RedrawWindow();
	
	return TRUE;
}

BOOL CEXScrollBar::GetScrollInfo(LPSCROLLINFO lpScrollInfo, 
                                 UINT nMask /*= SIF_ALL*/)
{
	if (IsBadWritePtr(lpScrollInfo, sizeof (SCROLLINFO)))
		return FALSE;

	if (lpScrollInfo->fMask & SIF_RANGE)
	{ 
		lpScrollInfo->nMin = m_nMin;
		lpScrollInfo->nMax = m_nMax;
	}

	if (lpScrollInfo->fMask & SIF_PAGE)
	{
		lpScrollInfo->nPage = m_nPage;
	}

	if (lpScrollInfo->fMask & SIF_POS)
	{
		lpScrollInfo->nPos = m_nPos;
	}

	if (lpScrollInfo->fMask & SIF_TRACKPOS)
	{
		lpScrollInfo->nTrackPos = m_nTrackPos;
	}	

	return TRUE;
}

int CEXScrollBar::GetScrollPos() const
{
	return m_nPos;
}

int CEXScrollBar::SetScrollPos(int nPos, BOOL bRedraw /*= TRUE*/)
{
	int nTemp = m_nPos;
	m_nPos = nPos;

	CRect rcClient;
	GetClientRect(rcClient);
	UpdateThumbPosition(rcClient);

	if (bRedraw)
		RedrawWindow();

	return nTemp;
}

void CEXScrollBar::GetScrollRange(LPINT lpMinPos, LPINT lpMaxPos) const
{
	ASSERT(lpMinPos && lpMinPos);

	*lpMinPos = m_nMin;
	*lpMaxPos = m_nMax;
}

void CEXScrollBar::SetScrollRange(int nMinPos, int nMaxPos, 
                                  BOOL bRedraw /*= TRUE*/)
{
	m_nMin = nMinPos;
	m_nMax = nMaxPos;

	if (bRedraw)
		RedrawWindow();
}

int CEXScrollBar::GetScrollLimit()
{
	return m_nMax;
}

void CEXScrollBar::OnPaint()
{
	CPaintDC dc(this); 

	DrawScroll(&dc);
}

void CEXScrollBar::OnSize(UINT nType, int cx, int cy)
{
	CWnd::OnSize(nType, cx, cy);

	CalcScroll(CRect(0, 0, cx, cy), TRUE);

	if (IsWindow(GetSafeHwnd()))
	{
		if (m_bSetLeftUpBitmap)
			SetLeftUpButtonBitmap(m_nLeftUpBitmapID, m_nLeftUpPic);

		if (m_bSetRightDownBitmap)
			SetRightDownButtonBitmap(m_nRightDownBitmapID, m_nRightDownPic);

		if (m_bSetPageBitmap)
			SetPageButtonBitmap(m_nPageBitmapID, m_nPagePic);

		CalcScroll(CRect(0, 0, cx, cy), TRUE);

		Invalidate();
	}
}

void CEXScrollBar::FreeTimer()
{
	if (m_nLeftUpTimerID)
	{
		KillTimer(DEF_TIMER_LEFT_PRESSED_ID);
		m_nLeftUpTimerID = 0;
	}

	if (m_nRightDownTimerID)
	{
		KillTimer(DEF_TIMER_RIGHT_PRESSED_ID);
		m_nRightDownTimerID = 0;
	}

	if (m_nPageLeftUpTimerID)
	{
		ReleaseCapture();
		KillTimer(DEF_TIMER_PAGE_LEFT_PRESSED_ID);
		m_nPageLeftUpTimerID = 0;
	}

	if (m_nPageRightDownTimerID)
	{
		KillTimer(DEF_TIMER_PAGE_RIGHT_PRESSED_ID);
		m_nPageRightDownTimerID = 0;
	}

	m_bClick = FALSE;
	ReleaseCapture();
}

LRESULT CEXScrollBar::OnMouseWheelNotify(WPARAM w, LPARAM l)
{
	CRect rcClient;
	GetClientRect(rcClient);
	GetParent()->SendMessage(WM_VSCROLL, MAKEWPARAM(w, 0), (LPARAM)GetSafeHwnd());
	UpdateThumbPosition(rcClient);
	return 0;
}

void CEXScrollBar::OnLButtonDown(UINT nFlags, CPoint point)
{
	FreeTimer();

	SetCapture();

	CRect rcClient;
	GetClientRect(rcClient);

	if (m_rcLeftUpArrow.PtInRect(point))
	{
		if (m_uLeftUpTimer)
		{
			KillTimer(DEF_TIMER_LEFT_LEAVE_ID);
			m_uLeftUpTimer = 0;
		}

		m_LeftUpSkin = SKIN_SELECT;
		m_RightDownSkin = SKIN_NORMAL;

		m_bClick = TRUE;
		GetParent()->SendMessage(m_bHorizontal ? WM_HSCROLL : WM_VSCROLL, 
      MAKEWPARAM(SB_LINELEFT, 0), (LPARAM)GetSafeHwnd());

		m_nLeftUpTimerID = SetTimer(DEF_TIMER_LEFT_PRESSED_ID, 
      DEF_TIMER_LEFT_PRESSED_ELAPSE, NULL);

		UpdateThumbPosition(rcClient);
	}
	else if (m_rcRightDownArrow.PtInRect(point))
	{
		if (m_uRightDownTimer)
		{
			KillTimer(DEF_TIMER_RIGHT_LEAVE_ID);
			m_uRightDownTimer = 0;
		}

		m_LeftUpSkin = SKIN_NORMAL;
		m_RightDownSkin = SKIN_SELECT;

		m_bClick = TRUE;
		GetParent()->SendMessage(m_bHorizontal ? WM_HSCROLL : WM_VSCROLL, 
      MAKEWPARAM(SB_LINERIGHT, 0), (LPARAM)GetSafeHwnd());

		m_nRightDownTimerID = SetTimer(DEF_TIMER_RIGHT_PRESSED_ID, 
      DEF_TIMER_RIGHT_PRESSED_ELAPSE, NULL);

		UpdateThumbPosition(rcClient);
	}
	else
	{
		if (!m_rcThumb.PtInRect(point) && m_rcScroll.PtInRect(point))
		{
			if(m_bHorizontal && point.x < m_rcThumb.left)
			{
				m_bClick = TRUE;
				m_nPageLeftUpTimerID = SetTimer(DEF_TIMER_PAGE_LEFT_PRESSED_ID, 
          DEF_TIMER_PAGE_LEFT_PRESSED_ELAPSE, NULL);

				GetParent()->SendMessage(m_bHorizontal ? WM_HSCROLL : WM_VSCROLL, 
          MAKEWPARAM(SB_PAGELEFT, 0), (LPARAM)GetSafeHwnd());

				UpdateThumbPosition(rcClient);
			}
			else if(!m_bHorizontal && point.y < m_rcThumb.top)
			{
				m_bClick = TRUE;
				m_nPageLeftUpTimerID = SetTimer(DEF_TIMER_PAGE_LEFT_PRESSED_ID, 
          DEF_TIMER_PAGE_LEFT_PRESSED_ELAPSE, NULL);

				GetParent()->SendMessage(m_bHorizontal ? WM_HSCROLL : WM_VSCROLL, 
          MAKEWPARAM(SB_PAGELEFT, 0), (LPARAM)GetSafeHwnd());

				UpdateThumbPosition(rcClient);
			}
			else
			{
				m_bClick = TRUE;
				m_nPageRightDownTimerID = SetTimer(DEF_TIMER_PAGE_RIGHT_PRESSED_ID, 
          DEF_TIMER_PAGE_RIGHT_PRESSED_ELAPSE, NULL);
				GetParent()->SendMessage(m_bHorizontal ? WM_HSCROLL : WM_VSCROLL, 
          MAKEWPARAM(SB_PAGERIGHT, 0), (LPARAM)GetSafeHwnd());
				UpdateThumbPosition(rcClient);
			}
		}
	}

	CWnd::OnLButtonDown(nFlags, point);
}

void CEXScrollBar::OnLButtonUp(UINT nFlags, CPoint point)
{
	if (m_rcLeftUpArrow.PtInRect(point))
		m_LeftUpSkin = SKIN_FOCUS;
	else
		m_LeftUpSkin = SKIN_NORMAL;

	if (m_rcRightDownArrow.PtInRect(point))
		m_RightDownSkin = SKIN_FOCUS;
	else
		m_RightDownSkin = SKIN_NORMAL;

	FreeTimer();

	m_ptPrevPos.x = 0;
	m_ptPrevPos.y = 0;

	CRect rcClient;
	GetClientRect(rcClient);
	UpdateThumbPosition(rcClient);

	CWnd::OnLButtonUp(nFlags, point);
}

void CEXScrollBar::SetThumbPosition(CRect & rcThumb, BOOL bContinued)
{
	if (m_bHorizontal)
		rcThumb.InflateRect(0, 1, 0, 1);
	else
		rcThumb.InflateRect(1, 0, 1, 0);

	m_bContinued = bContinued;

	m_rcThumb = rcThumb;
	SetPositionFromThumb();
	GetParent()->SendMessage(m_bHorizontal ? WM_HSCROLL : WM_VSCROLL, 
    MAKEWPARAM(SB_THUMBTRACK, m_nPos), (LPARAM)GetSafeHwnd());
}

void CEXScrollBar::OnTimer(UINT_PTR nIDEvent)
{
	CPoint ptCurrent;
	GetCursorPos(&ptCurrent);
	ScreenToClient(&ptCurrent);

	CRect rcClient;
	GetClientRect(rcClient);

	if (nIDEvent == DEF_TIMER_LEFT_PRESSED_ID)
	{
		if (m_rcLeftUpArrow.PtInRect(ptCurrent))
		{
			GetParent()->SendMessage(m_bHorizontal ? WM_HSCROLL : WM_VSCROLL, 
        MAKEWPARAM(SB_LINELEFT, 0), (LPARAM)GetSafeHwnd());
			UpdateThumbPosition(rcClient);
		}
	}
	else if (nIDEvent == DEF_TIMER_RIGHT_PRESSED_ID)
	{
		if (m_rcRightDownArrow.PtInRect(ptCurrent))
		{
			GetParent()->SendMessage(m_bHorizontal ? WM_HSCROLL : WM_VSCROLL, 
        MAKEWPARAM(SB_LINERIGHT, 0), (LPARAM)GetSafeHwnd());
			UpdateThumbPosition(rcClient);
		}
	}
	else if (nIDEvent == DEF_TIMER_PAGE_LEFT_PRESSED_ID)
	{
		if (m_rcScrollLeftUp.PtInRect(ptCurrent))
		{
			GetParent()->SendMessage(m_bHorizontal ? WM_HSCROLL : WM_VSCROLL, 
        MAKEWPARAM(SB_PAGELEFT, 0), (LPARAM)GetSafeHwnd());
			UpdateThumbPosition(rcClient);
		}
	}
	else if (nIDEvent == DEF_TIMER_PAGE_RIGHT_PRESSED_ID)
	{
		if (m_rcScrollRightDown.PtInRect(ptCurrent))
		{
			GetParent()->SendMessage(m_bHorizontal ? WM_HSCROLL : WM_VSCROLL, 
        MAKEWPARAM(SB_PAGERIGHT, 0), (LPARAM)GetSafeHwnd());
			UpdateThumbPosition(rcClient);
		}
	}
	else if (nIDEvent == DEF_TIMER_LEFT_LEAVE_ID)
	{
		POINT ptCur;
		GetCursorPos(&ptCur);
		ScreenToClient(&ptCur);

		if (!m_rcLeftUpArrow.PtInRect(ptCur))
		{
			KillTimer(DEF_TIMER_LEFT_LEAVE_ID);
			m_uLeftUpTimer = 0;
			m_LeftUpSkin = SKIN_NORMAL;
			RedrawWindow(NULL, NULL, RDW_UPDATENOW|RDW_NOERASE|RDW_INVALIDATE);
		}
	}
	else if (nIDEvent == DEF_TIMER_RIGHT_LEAVE_ID)
	{
		POINT ptCur;
		GetCursorPos(&ptCur);
		ScreenToClient(&ptCur);

		if (!m_rcRightDownArrow.PtInRect(ptCur))
		{
			KillTimer(DEF_TIMER_RIGHT_LEAVE_ID);
			m_uRightDownTimer = 0;
			m_RightDownSkin = SKIN_NORMAL;
			RedrawWindow(NULL, NULL, RDW_UPDATENOW|RDW_NOERASE|RDW_INVALIDATE);
		}
	}

	CWnd::OnTimer(nIDEvent);
}

void CEXScrollBar::LimitThumbPosition(CRect & rcClient)
{
	if (m_bHorizontal)
	{
		if (m_rcThumb.Width() < 20)
			m_rcThumb.right = m_rcThumb.left + 20;

		if (m_rcThumb.right > m_rcRightDownArrow.left)
		{
			int nTemp = m_rcThumb.Width();
			m_rcThumb.left = m_rcRightDownArrow.left - nTemp;
			m_rcThumb.right = m_rcThumb.left + nTemp;

		}

		if (m_rcThumb.left < (rcClient.left + m_rcLeftUpArrow.Width()))
		{
			int nTemp = m_rcThumb.Width();
			m_rcThumb.left = rcClient.left + m_rcLeftUpArrow.Width();
			m_rcThumb.right = m_rcThumb.left + nTemp;
		}
	}
	else
	{
		if (m_rcThumb.Height() < 20)
			m_rcThumb.bottom = m_rcThumb.top + 20;

		if (m_rcThumb.bottom > m_rcRightDownArrow.top)
		{
			int nTemp = m_rcThumb.Height();
			m_rcThumb.bottom = rcClient.Height() - m_rcRightDownArrow.Height();
			m_rcThumb.top = m_rcThumb.bottom - nTemp;
		}

		if (m_rcThumb.bottom < (rcClient.top + m_rcLeftUpArrow.Height()))
		{
			int nTemp = m_rcThumb.Height();
			m_rcThumb.top = rcClient.top + m_rcLeftUpArrow.Height();
			m_rcThumb.bottom = m_rcThumb.top + nTemp;
		}
	}
}

void CEXScrollBar::SetPositionFromThumb()
{
	CRect rcClient;
	GetClientRect(rcClient);
	LimitThumbPosition(rcClient);

	double dPixels, dMax, dInterval, dPos;

	dMax = m_nMax-m_nMin;

	if (m_bHorizontal)
	{
		dPixels   = m_rcScroll.Width() - m_rcThumb.Width();
		dInterval = dPixels / (dMax-m_nPage);
		dPos = ((m_rcThumb.left - m_rcLeftUpArrow.right) / dInterval);
	}
	else
	{
		dPixels   = m_rcScroll.Height() - m_rcThumb.Height();
		dInterval = dPixels / (dMax-m_nPage);
		dPos = (m_rcThumb.top - m_rcLeftUpArrow.bottom) / dInterval;
	}

	int nPrevPos = m_nPos;
	m_nPos = (int) (dPos + 0.5);

	if (m_bContinued && m_nPos == (m_nMax-m_nPage))
		m_nPos++;

	m_bContinued = FALSE;

	if (m_nPos < m_nMin)
		m_nPos = m_nMin;
	else if (m_nPos > m_nMax)
		m_nPos = m_nMax;
}

void CEXScrollBar::UpdateThumbPosition(CRect & rcClient)
{
	double dPixels, dMax, dInterval, dPos;

	dMax = m_nMax-m_nMin;
	dPos = m_nPos;

	if (m_bHorizontal)
	{
		dPixels   = m_rcScroll.Width() - m_rcThumb.Width();
		dInterval = dPixels / (dMax-m_nPage);
		double dThumbLeft = dPos * dInterval + 0.5;

		m_rcThumb.left = m_rcLeftUpArrow.right + (int)dThumbLeft;
		m_rcThumb.right = m_rcThumb.left + m_siThumb.cx;
		m_rcThumb.top = 0;
		m_rcThumb.bottom = m_siThumb.cy;
	}
	else
	{
		dPixels   = rcClient.Height() - (m_rcLeftUpArrow.Height() +
                m_rcThumb.Height()+m_rcRightDownArrow.Height());

		dInterval = dPixels / (dMax-m_nPage);
		double dThumbTop = dPos * dInterval + 0.5;

		m_rcThumb.top = m_rcLeftUpArrow.Height() + (int)dThumbTop;
		m_rcThumb.bottom = m_rcThumb.top + m_siThumb.cy;
		m_rcThumb.left = 0;
		m_rcThumb.right = m_siThumb.cx;
	}

	LimitThumbPosition(rcClient);

	m_rcScrollLeftUp = m_rcScrollRightDown = m_rcScroll;

	if (m_bHorizontal)
	{
		m_rcScrollLeftUp.right = m_rcThumb.left;
		m_rcScrollRightDown.left = m_rcThumb.right;
	}
	else
	{
		m_rcScrollLeftUp.bottom = m_rcThumb.top;
		m_rcScrollRightDown.top = m_rcThumb.bottom;
	}

	if (IsWindow(GetSafeHwnd()))
	{
		CClientDC dc(this);
		DrawScroll(&dc);
	}

	if (IsWindow(m_wndThumb.GetSafeHwnd()))
	{
		m_wndThumb.MoveWindow(m_rcThumb);
	}
}

void CEXScrollBar::DrawScroll(CDC * pDC)
{
	CRect rcClient;
	GetClientRect(rcClient);

	CDC dcBkgnd;
	dcBkgnd.CreateCompatibleDC(pDC);

	CBitmap bmpBkgnd;
	bmpBkgnd.CreateCompatibleBitmap(pDC, rcClient.Width(), rcClient.Height());

	CBitmap * pOldBitmap = NULL;
	pOldBitmap = dcBkgnd.SelectObject(&bmpBkgnd);

	dcBkgnd.FillSolidRect(&rcClient, GetSysColor(COLOR_SCROLLBAR));

	CBitmap * pOldImageBitmap;

	CDC dcBitmap;
	dcBitmap.CreateCompatibleDC(pDC);

	if (m_bSetLeftUpBitmap)
	{
		BITMAP bmLeftUp;
		m_bmpLeftUp.GetBitmap(&bmLeftUp);

		pOldImageBitmap = dcBitmap.SelectObject(&m_bmpLeftUp);

		STATUS st;

		if (!IsWindowEnabled())
		{
			st = disable;
		}
		else
		{
			if (m_LeftUpSkin == SKIN_FOCUS)
				st = focus;
			else if (m_LeftUpSkin == SKIN_SELECT)
				st = select;
			else
				st = normal;
		}

		int nWidth = bmLeftUp.bmWidth / m_nLeftUpPic;

		dcBkgnd.TransparentBlt(m_rcLeftUpArrow.left, m_rcLeftUpArrow.top, 
      m_rcLeftUpArrow.Width(), m_rcLeftUpArrow.Height(),
			&dcBitmap, nWidth*st, 0, nWidth, bmLeftUp.bmHeight, RGB(255,0,255));

		dcBitmap.SelectObject(pOldImageBitmap);
	}
	else
	{
		BITMAP bmLeftUp;
		m_bmpLeftUp.GetBitmap(&bmLeftUp);

		CRect rcLeftUpArrow;
		rcLeftUpArrow.left = m_rcLeftUpArrow.left + ((m_rcLeftUpArrow.Width() - 
      bmLeftUp.bmWidth) / 2);

		rcLeftUpArrow.right = rcLeftUpArrow.left + bmLeftUp.bmWidth;

		rcLeftUpArrow.top = m_rcLeftUpArrow.top + ((m_rcLeftUpArrow.Height() - 
      bmLeftUp.bmHeight) / 2);

		rcLeftUpArrow.bottom = rcLeftUpArrow.top + bmLeftUp.bmHeight;

		CRect rcLArrow(m_rcLeftUpArrow);

		if (m_nLeftUpTimerID)
		{
			dcBkgnd.Draw3dRect(&rcLArrow, RGB(128, 128, 128), RGB(128, 128, 128));
			rcLeftUpArrow.OffsetRect(1, 1);
		}
		else
		{
			dcBkgnd.Draw3dRect(&rcLArrow, RGB(192, 192, 192), RGB(0, 0, 0));
			rcLArrow.DeflateRect(1, 1);
			dcBkgnd.Draw3dRect(&rcLArrow, RGB(255, 255, 255), RGB(128, 128, 128));
		}

		pOldImageBitmap = dcBitmap.SelectObject(&m_bmpLeftUp);
		dcBkgnd.TransparentBlt(rcLeftUpArrow.left, rcLeftUpArrow.top, 
      rcLeftUpArrow.Width(), rcLeftUpArrow.Height(),
			&dcBitmap, 0, 0, bmLeftUp.bmWidth, bmLeftUp.bmHeight, RGB(255,0,255));

		dcBitmap.SelectObject(pOldImageBitmap);
	}

	if (m_bSetRightDownBitmap)
	{
		BITMAP bmRightDown;
		m_bmpRightDown.GetBitmap(&bmRightDown);

		pOldImageBitmap = dcBitmap.SelectObject(&m_bmpRightDown);

		STATUS st;

		if (!IsWindowEnabled())
			st = disable;
		else
		{
			if (m_RightDownSkin == SKIN_FOCUS)
				st = focus;
			else if (m_RightDownSkin == SKIN_SELECT)
				st = select;
			else
				st = normal;
		}

		int nWidth = bmRightDown.bmWidth / m_nRightDownPic;

		dcBkgnd.TransparentBlt(m_rcRightDownArrow.left, m_rcRightDownArrow.top, 
      m_rcRightDownArrow.Width(), m_rcRightDownArrow.Height(),
			&dcBitmap, nWidth*st, 0, nWidth, bmRightDown.bmHeight, RGB(255,0,255));

		dcBitmap.SelectObject(pOldImageBitmap);
	}
	else
	{
		BITMAP bmRightDown;
		m_bmpRightDown.GetBitmap(&bmRightDown);

		CRect rcRightDownArrow;
		rcRightDownArrow.left = m_rcRightDownArrow.left + 
      ((m_rcRightDownArrow.Width() - bmRightDown.bmWidth) / 2);

		rcRightDownArrow.right = rcRightDownArrow.left + bmRightDown.bmWidth;

		rcRightDownArrow.top = m_rcRightDownArrow.top + 
      ((m_rcRightDownArrow.Height() - bmRightDown.bmHeight) / 2);

		rcRightDownArrow.bottom = rcRightDownArrow.top + bmRightDown.bmHeight;

		CRect rcRArrow(m_rcRightDownArrow);

		if (m_nRightDownTimerID)
		{
			dcBkgnd.Draw3dRect(&rcRArrow, RGB(128, 128, 128), RGB(128, 128, 128));
			rcRightDownArrow.OffsetRect(1, 1);
		}
		else
		{
			dcBkgnd.Draw3dRect(&rcRArrow, RGB(192, 192, 192), RGB(0, 0, 0));
			rcRArrow.DeflateRect(1, 1);
			dcBkgnd.Draw3dRect(&rcRArrow, RGB(255, 255, 255), RGB(128, 128, 128));
		}

		pOldImageBitmap = dcBitmap.SelectObject(&m_bmpRightDown);

		dcBkgnd.TransparentBlt(rcRightDownArrow.left, rcRightDownArrow.top, 
      rcRightDownArrow.Width(), rcRightDownArrow.Height(), &dcBitmap, 0, 0, 
      bmRightDown.bmWidth, bmRightDown.bmHeight, RGB(255,0,255));

		dcBitmap.SelectObject(pOldImageBitmap);
	}

	if (m_bSetPageBitmap)
	{
		CBrush brPageNormal;
		CBrush brPageClick;

		BITMAP bmInfo;
		m_bmpPageNormal.GetBitmap(&bmInfo);

		int nWidth = bmInfo.bmWidth/m_nPagePic;

		CDC dcPage;
		dcPage.CreateCompatibleDC(pDC);

		CBitmap * pOldPageBitmap = dcPage.SelectObject(&m_bmpPageNormal);

		CDC dcMemory;
		dcMemory.CreateCompatibleDC(pDC);

		CBitmap bmpMemory;
		bmpMemory.CreateCompatibleBitmap(pDC, nWidth, bmInfo.bmHeight);

		CBitmap * pOldeBitmap = dcMemory.SelectObject(&bmpMemory);

		if (!IsWindowEnabled())
		{
			dcMemory.BitBlt(0, 0, nWidth, bmInfo.bmHeight, 
        &dcPage, nWidth*disable, 0, SRCCOPY);

			dcMemory.SelectObject(pOldeBitmap);

			brPageNormal.CreatePatternBrush(&bmpMemory);
			brPageClick.CreatePatternBrush(&bmpMemory);
		}
		else
		{
			dcMemory.BitBlt(0, 0, nWidth, bmInfo.bmHeight, 
        &dcPage, nWidth*normal, 0, SRCCOPY);

			dcMemory.SelectObject(pOldeBitmap);

			brPageNormal.CreatePatternBrush(&bmpMemory);

			pOldeBitmap = dcMemory.SelectObject(&bmpMemory);
			dcMemory.BitBlt(0, 0, nWidth, bmInfo.bmHeight, 
        &dcPage, nWidth*select, 0, SRCCOPY);

			dcMemory.SelectObject(pOldeBitmap);

			brPageClick.CreatePatternBrush(&bmpMemory);
		}

		dcPage.SelectObject(pOldPageBitmap);

		CRect rcScrollLeftUp(m_rcScrollLeftUp);
		CRect rcScrollRightDown(m_rcScrollRightDown);

		if (m_bHorizontal)
		{
			rcScrollLeftUp.right += (m_rcThumb.Width() / 2);
			rcScrollRightDown.left -= (m_rcThumb.Width() / 2);
		}
		else
		{
			rcScrollLeftUp.bottom += (m_rcThumb.Height() / 2);
			rcScrollRightDown.top -= (m_rcThumb.Height() / 2);
		}

		dcBkgnd.FillRect(&rcScrollLeftUp, m_nPageLeftUpTimerID ? 
                     &brPageClick : &brPageNormal);

		dcBkgnd.FillRect(&rcScrollRightDown, m_nPageRightDownTimerID ? 
                      &brPageClick : &brPageNormal);
	}
	else
	{
		CBrush brPageNormal;
		CBrush brPageClick;

		if (!IsWindowEnabled())
		{
			brPageNormal.CreatePatternBrush(&m_bmpPageDisable);
			brPageClick.CreatePatternBrush(&m_bmpPageDisable);
		}
		else
		{
			brPageNormal.CreatePatternBrush(&m_bmpPageNormal);
			brPageClick.CreatePatternBrush(&m_bmpPageSelect);
		}

		CRect rcScrollLeftUp(m_rcScrollLeftUp);
		CRect rcScrollRightDown(m_rcScrollRightDown);

		if (m_bHorizontal)
		{
			rcScrollLeftUp.right += (m_rcThumb.Width() / 2);
			rcScrollRightDown.left -= (m_rcThumb.Width() / 2);
		}
		else
		{
			rcScrollLeftUp.bottom += (m_rcThumb.Height() / 2);
			rcScrollRightDown.top -= (m_rcThumb.Height() / 2);
		}

		dcBkgnd.FillRect(&rcScrollLeftUp, m_nPageLeftUpTimerID ? 
      &brPageClick : &brPageNormal);

		dcBkgnd.FillRect(&rcScrollRightDown, m_nPageRightDownTimerID ? 
      &brPageClick : &brPageNormal);
	}

	pDC->BitBlt(0,0,rcClient.Width(), rcClient.Height(), &dcBkgnd, 0, 0, SRCCOPY);

	dcBkgnd.SelectObject(pOldBitmap);
	pOldBitmap = NULL;
}

void CEXScrollBar::OnDestroy()
{
	CWnd::OnDestroy();

	m_wndThumb.DestroyWindow();
}

int CEXScrollBar::SetArrowSize(int nSize)
{
	int nPrevSize = m_nArrowSize;
	m_nArrowSize = nSize;

	CRect rcClient;
	GetClientRect(rcClient);
	CalcScroll(rcClient, TRUE);

	return nPrevSize;
}

BOOL CEXScrollBar::SetLeftUpButtonBitmap(UINT nID, int nPics)
{
	CBitmap bmp;
	if( !bmp.LoadBitmap(nID) )
		return FALSE;

	m_bmpLeftUp.DeleteObject();

	if( !InitBgBitmap( bmp, m_bmpLeftUp, normal, nPics ) )
		return FALSE;
	if( !InitBgBitmap( bmp, m_bmpLeftUp, select, nPics ) )
		return FALSE;
	if( !InitBgBitmap( bmp, m_bmpLeftUp, disable, nPics ) )
		return FALSE;
	if( !InitBgBitmap( bmp, m_bmpLeftUp, focus, nPics ) )
		return FALSE;

	bmp.DeleteObject();

	m_nLeftUpBitmapID = nID;
	m_nLeftUpPic = nPics;
	m_bSetLeftUpBitmap = TRUE;

	return TRUE;
}

BOOL CEXScrollBar::SetRightDownButtonBitmap(UINT nID, int nPics)
{
	CBitmap bmp;
	if( !bmp.LoadBitmap(nID) )
		return FALSE;

	m_bmpRightDown.DeleteObject();

	if( !InitBgBitmap( bmp, m_bmpRightDown, normal, nPics ) )
		return FALSE;
	if( !InitBgBitmap( bmp, m_bmpRightDown, select, nPics ) )
		return FALSE;
	if( !InitBgBitmap( bmp, m_bmpRightDown, disable, nPics ) )
		return FALSE;
	if( !InitBgBitmap( bmp, m_bmpRightDown, focus, nPics ) )
		return FALSE;

	bmp.DeleteObject();

	m_nRightDownBitmapID = nID;
	m_nRightDownPic = nPics;
	m_bSetRightDownBitmap = TRUE;

	return TRUE;
}

BOOL CEXScrollBar::SetPageButtonBitmap(UINT nID, int nPics)
{
	CBitmap bmp;
	if( !bmp.LoadBitmap(nID) )
		return FALSE;

	m_bmpPageNormal.DeleteObject();
	m_bmpPageSelect.DeleteObject();
	m_bmpPageDisable.DeleteObject();
	m_bmpPageFocus.DeleteObject();

	if( !InitBgBitmap( bmp, m_bmpPageNormal, normal, nPics, FALSE ) )
		return FALSE;

	if( !InitBgBitmap( bmp, m_bmpPageNormal, select, nPics, FALSE ) )
		return FALSE;

	if( !InitBgBitmap( bmp, m_bmpPageNormal, disable, nPics, FALSE ) )
		return FALSE;

	if( !InitBgBitmap( bmp, m_bmpPageNormal, focus, nPics, FALSE ) )
		return FALSE;

	bmp.DeleteObject();

	m_nPageBitmapID = nID;
	m_nPagePic = nPics;
	m_bSetPageBitmap = TRUE;

	return TRUE;
}

BOOL CEXScrollBar::SetThumbBitmap(UINT nThumbID, UINT nBkgndID, UINT nIconID, 
                                  int nPics, int nLeftWidth /*= 0*/, 
                                  int nRightWidth /*= 0*/, 
                                  int nTopHeight /*= 0*/, 
                                  int nBottomHeight /*= 0*/)
{
	return m_wndThumb.SetThumbBitmap(nThumbID, nBkgndID, nIconID, nPics, 
    nLeftWidth, nRightWidth, nTopHeight, nBottomHeight);
}

BOOL CEXScrollBar::InitBgBitmap( CBitmap & bmpSrc, CBitmap & bmpDest, 
                                int nIndex, int nCount, BOOL bReSize )
{
	CDC * pDC = GetDC();

	CDC memDC; 
	memDC.CreateCompatibleDC(pDC);

	CDC srcDC;
	srcDC.CreateCompatibleDC(pDC);

	CBitmap* pOldBitmap1;
	pOldBitmap1 = srcDC.SelectObject(&bmpSrc);

	BITMAP bmpinfo;
	bmpSrc.GetBitmap(&bmpinfo);
	int bmpWidth = bmpinfo.bmWidth / nCount;
	int bmpHeight = bmpinfo.bmHeight;
	int orix = bmpWidth * (nIndex < nCount ? nIndex : 0);

	CRect rc;
	GetClientRect(rc);

	if (!bmpDest.GetSafeHandle())
		bmpDest.CreateCompatibleBitmap(pDC,rc.Width()*nCount,rc.Height());

	CBitmap* pOldBitmap2;
	pOldBitmap2 = memDC.SelectObject(&bmpDest);

	memDC.StretchBlt(rc.Width()*nIndex, 0, rc.Width(), rc.Height(), 
    &srcDC, orix, 0, bmpWidth, bmpHeight, SRCCOPY);

	srcDC.SelectObject(pOldBitmap1);
	memDC.SelectObject(pOldBitmap2);

	ReleaseDC(pDC);
	ReleaseDC(&srcDC);
	ReleaseDC(&memDC);

	if (bReSize)
	{
		if (m_bHorizontal)
		{
			if (IsWindow(GetParent()->GetSafeHwnd()))
				((CEXListCtrlWnd*)GetParent())->SetHScrollHeight(bmpHeight);
			SetArrowSize(bmpWidth);
		}
		else
		{
			if (IsWindow(GetParent()->GetSafeHwnd()))
				((CEXListCtrlWnd*)GetParent())->SetVScrollWidth(bmpWidth);
			SetArrowSize(bmpHeight);
		}
	}

	return TRUE;
}

void CEXScrollBar::OnMouseMove(UINT nFlags, CPoint point)
{
	if (nFlags & MK_LBUTTON)
	{

	}
	else
	{
		if (m_rcLeftUpArrow.PtInRect(point))
		{
			if (!m_uLeftUpTimer)
				m_uLeftUpTimer = SetTimer(DEF_TIMER_LEFT_LEAVE_ID, 
        DEF_TIMER_LEFT_LEAVE_ELAPSE, NULL);

			m_LeftUpSkin = SKIN_FOCUS;
		}

		if (m_rcRightDownArrow.PtInRect(point))
		{
			if (!m_uRightDownTimer)
				m_uRightDownTimer = SetTimer(DEF_TIMER_RIGHT_LEAVE_ID, 
        DEF_TIMER_RIGHT_LEAVE_ELAPSE, NULL);

			m_RightDownSkin = SKIN_FOCUS;
		}

		RedrawWindow(NULL, NULL, RDW_UPDATENOW|RDW_NOERASE|RDW_INVALIDATE);
	}

	CWnd::OnMouseMove(nFlags, point);
}

BOOL CEXScrollBar::OnEraseBkgnd(CDC* pDC)
{
	UNREFERENCED_PARAMETER(pDC);
	return FALSE;
}

void CEXScrollBar::SetListErase(BOOL bErase)
{
	GetParent()->SendMessage(UM_LIST_ERASE, (WPARAM)bErase);
}